package mirrormonkey.util.annotations.parsing.memberlevel;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import junit.framework.Assert;
import mirrormonkey.util.annotations.control.IRClass;
import mirrormonkey.util.annotations.parsing.AnnotationParser;
import mirrormonkey.util.annotations.parsing.ClassIR;
import mirrormonkey.util.annotations.parsing.FieldIR;
import mirrormonkey.util.annotations.parsing.MemberIR;

import org.junit.BeforeClass;
import org.junit.Test;

/**
 * Contains test cases concerning <tt>FieldIR</tt>, which is a simple IR to not
 * only collect the annotations of matching fields, but also the fields
 * themselves.<br>
 * 
 * Please note that as <tt>FieldIR</tt> is considered an extension class, this
 * test suite relies heavily on the correctness of core functions. This
 * especially includes correctness of member matching, which is tests in the
 * proper management and collection test suites.
 * 
 * @author Philipp Christian Loewner
 * 
 */
public class FieldIRTest {

	public static AnnotationParser parser;

	@BeforeClass
	public static void setUpBeforeClass() {
		parser = new AnnotationParser();
	}

	public static class ValidityTestContainer {

		@IRClass
		public Object defaultIR;

		@IRClass(MemberIR.class)
		public Object memberCollectingIR;

	}

	public static class ExtendingValidityTestContainer {

		@IRClass(FieldIR.class)
		public Object defaultIR;

		@IRClass(FieldIR.class)
		public Object memberCollectingIR;

		@IRClass(FieldIR.class)
		public Object direct;
	}

	/**
	 * Tests if every INTERNAL member IR can be changed to this IR.
	 */
	@Test
	public void testValidity() {
		ClassIR ir = parser.parseClass(ExtendingValidityTestContainer.class,
				null);
		Assert.assertEquals(3, ir.memberIRs.get(Field.class).size());
		for (MemberIR i : ir.memberIRs.get(Field.class)) {
			Assert.assertEquals(FieldIR.class, i.getClass());
		}
		for (Class<?> i : new Class<?>[] { Constructor.class, Method.class }) {
			Assert.assertTrue(ir.memberIRs.get(i).isEmpty());
		}
	}

	public static class InvalidClass {

		@IRClass(FieldIR.class)
		public void method() {
		}

	}

	/**
	 * Tests if using a <tt>FieldIRTest</tt> on a method will provoke an
	 * exception.
	 */
	@Test(expected = RuntimeException.class)
	public void testRejectMethod() {
		parser.parseClass(InvalidClass.class, null);
	}

	public static class ContainingSingleField {

		@IRClass(FieldIR.class)
		public Object field;

	}

	/**
	 * Tests if fields are collected.
	 */
	@Test
	public void testCollectField() throws Exception {
		ClassIR ir = parser.parseClass(ContainingSingleField.class, null);
		Assert.assertEquals(((FieldIR) ir.memberIRs.get(Field.class).iterator()
				.next()).getCollectedField(),
				ContainingSingleField.class.getField("field"));
	}

	public static class ExtendingContainingSingleField extends
			ContainingSingleField {

		public Object field;

	}

	/**
	 * Tests if fields are not overridden.
	 */
	@Test
	public void testFieldCollectionOverride() throws Exception {
		ClassIR ir = parser.parseClass(ExtendingContainingSingleField.class,
				null);
		Assert.assertEquals(((FieldIR) ir.memberIRs.get(Field.class).iterator()
				.next()).getCollectedField(),
				ContainingSingleField.class.getField("field"));
	}
}
